package com.a0soft.gphone.aTruffleHog.wnd.info;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Alger Lin <addre75 (at) gmail.com>
 *
 */

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import com.a0soft.gphone.aTruffleHog.R;
import com.a0soft.gphone.aTruffleHog.di.DeviceInfo;
import com.a0soft.gphone.aTruffleHog.di.DeviceInfoKey;
import com.a0soft.gphone.aTruffleHog.di.SensorInfo;
import com.a0soft.gphone.aTruffleHog.util.CONSTS;
import com.a0soft.gphone.aTruffleHog.util.aDebug;
import org.json.JSONArray;
import org.json.JSONException;

/**Agent to handle view for sensor information.*/
public class InfoSSView {
    /**Tag for log.*/
    private static final String LOG_TAG = InfoSSView.class.getSimpleName();
    /**Symbol before data.*/
    private static final String SYMB_PREFIX = ": ";
    /**Symbol for new line.*/
    private static final String SYMB_NEWLINE = "\n";
    /**Symbol before unit.*/
    //private static final String SYMB_UNIT_PREFIX = " (";
    private static final String SYMB_UNIT_PREFIX = " ";
    /**Symbol after unit.*/
    //private static final String SYMB_UNIT_POSTFIX = ")";
    /**Invalid value of minimum delay.
     * Refer to description of android.hardware.Sensor.getMinDelay()*/
    private static final String VAL_MINDELAY_INVALID = "0.0";
    /**Application environment.*/
    private Context             m_oContext = null;
    /**Device information.*/
    private DeviceInfo          m_oInfo = null;
    
    /**Constructor.
     * @param oContext  [in] Application environment.
     * @param oInfo     [in] Device information.*/
    public
    InfoSSView(Context cxt, DeviceInfo di)
    {
        m_oContext = cxt;
        m_oInfo = di;
    }
    
    /**Get view for sensor information.
     * @param for_preview   [in] Flag to indicates preview status.
     * @return              Return view for sensor information.*/
    public View
    getView(boolean for_preview)
    {
        LinearLayout    returnObj = null;
        JSONArray       oType = null;
        int             iTypeLen = 0;
        
        //Initiate view
        returnObj = new LinearLayout(m_oContext);
        returnObj.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        returnObj.setOrientation(LinearLayout.VERTICAL);
        
        //Put sensor information into view
        if(((oType = m_oInfo.GetJSONArray(DeviceInfoKey.K.SS_AVAILABLE_TYPE)) != null) && ((iTypeLen = oType.length()) > 0)) {
            for(int a = 0; a < iTypeLen; a ++) {
                SensorInfo.KeySet   oKey = null;
                SensorData[]        oData = null;
                int                 iType = Integer.MIN_VALUE;
                
                //Get type of sensor
                try {
                    iType = Integer.parseInt(oType.getString(a));
                }
                catch(Exception ex) {
                    if(aDebug.ENABLED)
                        aDebug.e(LOG_TAG, "Get sensor type failed", ex);
                    continue;
                }
      
                //Get key of sensor
                if((oKey = SensorInfo.getKeySet(iType)) == null)
                    continue;
                //Get data of sensor
                else if((oData = SensorData.generateByDeviceInfo(m_oContext, m_oInfo, oKey)) == null)
                    continue;
                    
                //Handle value with array format
                for(int b = oData.length - 1; b >= 0; b --) {
                    View oView = LayoutInflater.from(m_oContext).inflate(R.layout.info_item, null);
                    InfoItemViewWrapper oWrap = new InfoItemViewWrapper(oView);
                    oView.setTag(oWrap);
                    oWrap.setItemName(DeviceInfoKey.GetName(oKey.getKey4SensorName()));
                    returnObj.addView(oView);
                    oWrap.setItemDetail(oData[b].toString());
                }
            }
        }
        //Show message if without valid data
        else {
            TextView    oTxt = new TextView(m_oContext);
            oTxt.setText(CONSTS.UNAVAILABLE);
            returnObj.addView(oTxt, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        }
        return returnObj;
    }
    
    /**Translate value of microseconds to milliseconds.
     * @param szVal [in] Value with string format in microseconds.
     * @return      Return translated value if succeeded, return null if failed.*/
    private static String translateMicrosecToMillisec(String szVal)
    {
        String returnObj = null;
        if(szVal != null) {
            float fVal = Float.NaN;
            try { 
                fVal = Float.parseFloat(szVal);
            }
            catch(NumberFormatException nfe) {
                if(aDebug.ENABLED)
                    aDebug.e(LOG_TAG, "Translate value failed", nfe);
            }
            if(fVal != Float.NaN) 
                returnObj = String.valueOf(fVal / 1000f);
        }
        return returnObj;
    }
    
    
    /**Wrapped information for one sensor.*/
    private static class SensorData {
        /**Application environment.*/
        private Context             m_oContext = null;
        /**Key set.*/
        private SensorInfo.KeySet   m_oKey = null;
        /**Name of sensor.*/
        private String              m_szName = null;
        /**Vender of sensor.*/
        private String              m_szVend = null;
        /**Version of sensor.*/
        private String              m_szVer = null;
        /**Power of sensor.*/
        private String              m_szPwr = null;
        /**Resolution of sensor.*/
        private String              m_szRes = null;
        /**Maximum value of sensor.*/
        private String              m_szMax = null;
        /**Minimum delay of sensor.*/
        private String              m_szDelay = null;
        
        /**Constructor.
         * @param oContext  [in] Application environment.
         * @param oKey      [in] Key set.*/
        private SensorData(Context oContext, SensorInfo.KeySet oKey)
        {
            m_oContext = oContext;
            m_oKey = oKey;
        }
        
        /**Create by single sensor item from device information.
         * @param oContext  [in] Application environment.
         * @param oInfo     [in] Device information.
         * @param oKey      [in] Key set.*/
        protected static SensorData[] generateByDeviceInfo(Context oContext, DeviceInfo oInfo, SensorInfo.KeySet oKey)
        {
            SensorData[]    returnObj = null;
            JSONArray       oNames = null;
            String          szName = null;
            if((oContext == null) || 
               (oInfo == null) ||
               (oKey == null)) {
            }
            //Handle if sensor information with array format
            else if((oNames = oInfo.GetJSONArray(oKey.getKey4SensorName())) != null) {
                JSONArray   oArr = null;
                
                //Prepare buffer for return
                returnObj = new SensorData[oNames.length()];
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    returnObj[a] = new SensorData(oContext.getApplicationContext(), oKey);
                    try {
                        returnObj[a].m_szName = oNames.getString(a);
                    } 
                    catch(JSONException je) {
                        returnObj[a].m_szName = CONSTS.UNAVAILABLE;
                    }
                }
                
                //Set information
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorVendor());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szVend = oArr.getString(a);
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szVend = CONSTS.UNAVAILABLE;
                    }
                }
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorVer());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szVer = oArr.getString(a);
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szVer = CONSTS.UNAVAILABLE;
                    }
                }
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorPwrConsumption());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szPwr = oArr.getString(a);
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szPwr = CONSTS.UNAVAILABLE;
                    }
                }
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorRes());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szRes = oArr.getString(a);
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szRes = CONSTS.UNAVAILABLE;
                    }
                }
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorMaxRange());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szMax = oArr.getString(a);
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szMax = CONSTS.UNAVAILABLE;
                    }
                }
                oArr = oInfo.GetJSONArray(oKey.getKey4SensorMinDelay());
                for(int a = oNames.length() - 1; a >= 0; a --) {
                    try {
                        returnObj[a].m_szDelay = translateMicrosecToMillisec(oArr.getString(a));
                    } 
                    catch(Exception ex) {
                        returnObj[a].m_szDelay = CONSTS.UNAVAILABLE;
                    }
                }
            }
            
            //Handle if sensor information with string format, for early edition
            else if((szName = oInfo.GetString(oKey.getKey4SensorName())) != null) {
                //Prepare buffer for return
                returnObj = new SensorData[] { new SensorData(oContext.getApplicationContext(), oKey) };
                
                //Set information
                returnObj[0].m_szName = szName;
                returnObj[0].m_szVend = oInfo.GetString(oKey.getKey4SensorVendor());
                returnObj[0].m_szVer = oInfo.GetString(oKey.getKey4SensorVer());
                returnObj[0].m_szPwr = oInfo.GetString(oKey.getKey4SensorPwrConsumption());
                returnObj[0].m_szRes = oInfo.GetString(oKey.getKey4SensorRes());
                returnObj[0].m_szMax = oInfo.GetString(oKey.getKey4SensorMaxRange());
                returnObj[0].m_szDelay = translateMicrosecToMillisec(oInfo.GetString(oKey.getKey4SensorMinDelay()));
            }
            return returnObj;
        }
        
        /**Returns a string representation of the object.
         * @return  a string representation of the object.*/
        @Override
        public String toString()
        {
            StringBuffer    returnObj = new StringBuffer();
            returnObj.append(m_szName);
            returnObj.append(SYMB_NEWLINE);
            //Set detail information
            returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorVendor()));
            returnObj.append(SYMB_PREFIX);
            returnObj.append(m_szVend);
            returnObj.append(SYMB_NEWLINE);
            returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorVer()));
            returnObj.append(SYMB_PREFIX);
            returnObj.append(m_szVer);
            if((m_szPwr != null) &&
               !CONSTS.UNAVAILABLE.equalsIgnoreCase(m_szPwr)) {
                returnObj.append(SYMB_NEWLINE);
                returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorPwrConsumption()));
                returnObj.append(SYMB_PREFIX);
                returnObj.append(m_szPwr);
                returnObj.append(SYMB_UNIT_PREFIX);
                returnObj.append(m_oContext.getString(R.string.di_ss_unit_ma));
                //returnObj.append(SYMB_UNIT_POSTFIX);
            }
            if((m_szRes != null) &&
               !CONSTS.UNAVAILABLE.equalsIgnoreCase(m_szRes)) {
                returnObj.append(SYMB_NEWLINE);
                returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorRes()));
                returnObj.append(SYMB_PREFIX);
                returnObj.append(m_szRes);
                //returnObj.append(SYMB_UNIT_PREFIX);
                //returnObj.append(m_oContext.getString(R.string.di_ss_unit_val));
                //returnObj.append(SYMB_UNIT_POSTFIX);
            }
            if((m_szMax != null) &&
               !CONSTS.UNAVAILABLE.equalsIgnoreCase(m_szMax)) {
                returnObj.append(SYMB_NEWLINE);
                returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorMaxRange()));
                returnObj.append(SYMB_PREFIX);
                returnObj.append(m_szMax);
                //returnObj.append(SYMB_UNIT_PREFIX);
                //returnObj.append(m_oContext.getString(R.string.di_ss_unit_val));
                //returnObj.append(SYMB_UNIT_POSTFIX);
            }
            if((m_szDelay != null) &&
               !CONSTS.UNAVAILABLE.equalsIgnoreCase(m_szDelay) &&
               !VAL_MINDELAY_INVALID.equalsIgnoreCase(m_szDelay)) {
                returnObj.append(SYMB_NEWLINE);
                returnObj.append(DeviceInfoKey.GetName(m_oKey.getKey4SensorMinDelay()));
                returnObj.append(SYMB_PREFIX);
                returnObj.append(m_szDelay);
                returnObj.append(SYMB_UNIT_PREFIX);
                returnObj.append(m_oContext.getString(R.string.di_ss_unit_ms));
                //returnObj.append(SYMB_UNIT_POSTFIX);
            }
            return returnObj.toString();
        }
        
    };
}
